//#include "../Misc/DEHT.h"
//#include "../Misc/part3_shared.h"
//#include <assert.h>
//
///* ############ Helper function for text_export_rainbow_table */
//int printf_chain_to_file(RULE *preprocess, char* first_password, int chain_length,
//		int num_of_seeds, LONG_INDEX_PROJ* seeds, BasicHashFunctionPtr cryptHashPtr,
//		int cryptHashSize, FILE *fp, unsigned char *last_hash) {
//
//	int i;
//	LONG_INDEX_PROJ k;
//	LONG_INDEX_PROJ biggest_password = preprocess->number_of_possible_passwords;
//	unsigned char curr_hash[MAX_HASH_SIZE];
//	char hexa_hash[MAX_HASH_SIZE*2 + 1];
//	char curr_pass[MAX_INTPUT_SIZE];
//	int status;
//
//	strcpy(curr_pass, first_password);
//	for (i = 0; i <= num_of_seeds; i++) {
//		status = fprintf(fp, "%s\t", curr_pass);
//		printf("%d - %s ", i,curr_pass);
//		if (status < 0) {
//			fprintf(stderr, "problem writing to small file\n");
//			return -1;
//		}
//
//		cryptHash(cryptHashPtr, curr_pass, curr_hash);
//
//		if (i == num_of_seeds) {
//			memcpy(last_hash, curr_hash, cryptHashSize);
//		}
//
//		binary2hexa(curr_hash, cryptHashSize, hexa_hash, MAX_HASH_SIZE*2 + 1);
//		status = fprintf(fp, "%s\t", hexa_hash);
//		printf("%s\n", hexa_hash);
//		if (status < 0) {
//			fprintf(stderr, "problem writing to big file\n");
//			return -1;
//		}
//
//		if (i < num_of_seeds) {
//			k = pseudo_random_function(curr_hash, cryptHashSize, seeds[i]) % preprocess->number_of_possible_passwords;
//			//k %= biggest_password;
//			generate_kth_password(k,curr_pass, *preprocess);
//		}
//	}
//
//	fseek(fp, -1, SEEK_CUR);
//	status = fprintf(fp, "\n");
//
//	return 0;
//}
//
///* reads data from file until \0 */
//void data_fread(FILE *fp, char *output) {
//
//	int i, c;
//
//	i = 0;
//	while ((c = getc(fp)) != '\0') {
//		output[i] = c;
//		i++;
//	}
//	output[i] = '\0';
//}
//
//
//
//int main(int argc, char **argv) {
//
//	INI_PARAMS ini_params;
//	BasicHashFunctionPtr crypt_func;	
//	int crypt_func_size_in_bytes;
//	char** lexicon;
//	int status;
//	LONG_INDEX_PROJ lexicon_size = 0;
//	RULE rule;
//	DEHT *ht;
//	int num_of_seeds;
//	LONG_INDEX_PROJ *seeds = NULL;
//	int chain_length;
//	FILE *smallfp = NULL, *bigfp = NULL;
//	LONG_INDEX_PROJ i;
//	char hashed_seed[MAX_HASH_SIZE * 2 + 1];
//	DEHT_DISK_PTR end_of_file;
//	DEHT_DISK_PTR location_in_file;
//	char password[MAX_INTPUT_SIZE];
//	unsigned char key[MAX_HASH_SIZE];
//	char keyInHexa[33];
//	
//	char *small_name = "C:\temp\small.txt";
//	char *big_name = "C:\temp\big.txt";
//
//	/*
//    char* buf = NULL;
//	char **dict;
//	int dict_size;
//	*/
//
//	/* read .ini file */
//	if (argc != 2)
//	{
//		fprintf(stderr, "Error: Usage create_rainbow_table <preferences filename>\n");
//		exit(1);
//	}
//
//	/* load .ini file to struct */
//	ini_params = get_params_from_INI_file(argv[1]);
//	/* check params */
//	if (!strcmp(ini_params.HashFunction, "MD5")) {
//		crypt_func = MD5BasicHash;
//		crypt_func_size_in_bytes = MD5_OUTPUT_LENGTH_IN_BYTES;
//	} else if (!strcmp(ini_params.HashFunction, "SHA1")) {
//		crypt_func = SHA1BasicHash;
//		crypt_func_size_in_bytes = SHA1_OUTPUT_LENGTH_IN_BYTES;
//	} else {
//		fprintf(stderr, "Error: Hash %s is not supported\n", argv[1]);
//		exit(1);
//	}
//
//	if (ini_params.ChainLength < 1) {
//		fprintf(stderr, "Error: rainbow_chain_length in %s is %d. It should be positive number\n",
//				argv[1], ini_params.ChainLength);
//		exit(1);
//	}
//
//	if (ini_params.NumOfHashEntries < 1) {
//		fprintf(stderr, "Error: entries_in_hash_table in %s is %d. It should be a positive number\n",
//				argv[1], ini_params.NumOfHashEntries);
//		exit(1);
//	}
//
//	if (ini_params.ElementsInBucket < 1) {
//		fprintf(stderr, "Error: bucket_block_length in %s is %d. It should be a positive number\n",
//				argv[1], ini_params.ElementsInBucket);
//		exit(1);
//	}
//
// 	lexicon = load_lexicon(ini_params.LexiconName, &lexicon_size);
//	status = create_rule(&rule, ini_params.Rule, lexicon, lexicon_size);
//	if (status == -1) {
//		free_lexicon(lexicon, lexicon_size);
//		exit(1);
//	} 
//
//	/* load DEHT */
//	ht = load_DEHT_from_files(ini_params.OutputFilePrefix, cryptHashToTable, cryptHashTo64bit);
//	if (ht == NULL)
//	{
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	if (!strcmp(ht->header.sHashName, "MD5")) {
//		crypt_func = MD5BasicHash;
//		crypt_func_size_in_bytes = MD5_OUTPUT_LENGTH_IN_BYTES;
//	} else if (!strcmp(ht->header.sHashName, "SHA1")) {
//		crypt_func = SHA1BasicHash;
//		crypt_func_size_in_bytes = SHA1_OUTPUT_LENGTH_IN_BYTES;
//	} else {
//		fprintf(stderr, "Error: invalid DEHT structure\n");
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//
//	num_of_seeds = ini_params.ChainLength;
//	seeds = (LONG_INDEX_PROJ*) malloc( ini_params.ChainLength * sizeof(LONG_INDEX_PROJ));
//	if (seeds == NULL){
//		fprintf(stderr, "Error: not enough memory\n");
//		lock_DEHT_files(ht);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		exit(1);
//	}
//	
//	status = read_DEHT_Seed(ht, seeds , num_of_seeds);
//	if (status == DEHT_STATUS_FAIL) {
//		fprintf(stderr, "Error: failed to read seeds\n");
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		lock_DEHT_files(ht);
//		free(seeds);
//		exit(1);
//	}
//
//	
//	/*    */
//	//chain_length = ( num_of_seeds * 2 ) + 1;
//	chain_length = num_of_seeds;
//
//	smallfp = fopen(small_name, "w");
//	if (!smallfp) {
//		perror(small_name);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		lock_DEHT_files(ht);
//		free(seeds);
//		exit(1);
//	}
//
//	bigfp = fopen(big_name, "w");
//	if (!bigfp) {
//		perror(big_name);
//		free_lexicon(lexicon, lexicon_size);
//		free_rule(&rule);
//		lock_DEHT_files(ht);
//		free(seeds);
//		fclose(smallfp);
//		exit(1);
//	}
//
//	printf("dictionary_name = %s\n", ini_params.OutputFilePrefix);
//	printf("rainbow_chain_length = %d\n", chain_length);
//	printf("entries_in_hash_table = %d\n", ht->header.numEntriesInHashTable);
//	printf("bucket_block_length = %d\n", ht->header.nPairsPerBlock);
//
//	for (i = 0; i < num_of_seeds; i++) {
//		binary2hexa((unsigned char*)(seeds+i), sizeof(LONG_INDEX_PROJ), hashed_seed, MAX_INTPUT_SIZE*2+1);
//		status = fprintf(smallfp, "%s\n", hashed_seed);
//		if (status < 0) {
//			perror(argv[3]);
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			lock_DEHT_files(ht);
//			free(seeds);
//			fclose(smallfp);
//			fclose(bigfp);
//			exit(1);
//		}
//	}
//
//	fseek(ht->dataFP, 0, SEEK_END);
//	end_of_file = ftell(ht->dataFP);
//
//	/*move to the first password in file*/
//	fseek(ht->dataFP, 1, SEEK_SET);
//	location_in_file = ftell(ht->dataFP);
//
//	while (location_in_file != end_of_file) {
//		data_fread(ht->dataFP, password);
//		location_in_file = ftell(ht->dataFP);
//
//		status = fprintf(smallfp, "%s - ", password);
//		if (status < 0) {
//			perror(argv[3]);
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			lock_DEHT_files(ht);
//			free(seeds);
//			fclose(smallfp);
//			fclose(bigfp);
//			exit(1);
//		}
//
//		status = printf_chain_to_file(&rule, password, chain_length, num_of_seeds, seeds,
//				crypt_func, crypt_func_size_in_bytes, bigfp, key);
//
//		if (status < 0) {
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			lock_DEHT_files(ht);
//			free(seeds);
//			fclose(smallfp);
//			fclose(bigfp);
//			exit(1);
//		}
//
//		status = query_DEHT(ht, key, crypt_func_size_in_bytes, (unsigned char*)password, MAX_INTPUT_SIZE);
//		//assert( status != DEHT_STATUS_NOT_NEEDED && status != DEHT_STATUS_FAIL );
//		if (status == DEHT_STATUS_FAIL){
//			fprintf(stderr, "Error: querry deht failed\n");
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			lock_DEHT_files(ht);
//			free(seeds);
//			fclose(smallfp);
//			fclose(bigfp);
//			exit(1);
//		}
//		if (status == DEHT_STATUS_NOT_NEEDED){
//			binary2hexa(key, crypt_func_size_in_bytes, keyInHexa, 33);
//			fprintf(stderr, "Warning: no such key in DEHT: %s\n",keyInHexa);
//			status = fprintf(smallfp, "not found");
//			if (status < 0) {
//			perror(argv[3]);
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			lock_DEHT_files(ht);
//			free(seeds);
//			fclose(smallfp);
//			fclose(bigfp);
//			exit(1);
//		}
//		}
//
//		fseek(ht->dataFP, location_in_file, SEEK_SET);
//		status = fprintf(smallfp, "\n");
//		if (status < 0) {
//			perror(argv[3]);
//			free_lexicon(lexicon, lexicon_size);
//			free_rule(&rule);
//			lock_DEHT_files(ht);
//			free(seeds);
//			fclose(smallfp);
//			fclose(bigfp);
//			exit(1);
//		}
//
//	}
//
//	free_lexicon(lexicon, lexicon_size);
//	free_rule(&rule);
//	lock_DEHT_files(ht);
//	free(seeds);
//	fclose(smallfp);
//	fclose(bigfp);
//
//	return 0;
//}
